#region Using Statements
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
#endregion

namespace XnaGameComponents
{
    /// <summary>
    /// This is a game component that implements IUpdateable.
    /// </summary>
    public class ModelViewer : DrawableGameComponent, IMoveable
    {
        private Model myShip;

        private string modelPath;

        public string Model
        {
            get { return modelPath; }
            set { modelPath = value; }
        }

        protected Vector3 position;

        public Vector3 Position
        {
            get { return position; }
            set { position = value; }
        }

        private bool isGround;

        public bool IsGround
        {
            get { return isGround; }
            set { isGround = value; }
        }

        private bool isStair;

        public bool IsStair
        {
            get { return isStair; }
            set { isStair = value; }
        }





        public ModelViewer(Game game)
            : base(game)
        {
            // TODO: Construct any child components here
        }

        protected override void LoadContent()
        {
            base.LoadContent();
            myShip = new ContentManager(Game.Services).Load<Model>(modelPath);
        }


        /// <summary>
        /// Allows the game component to perform any initialization it needs to before starting
        /// to run.  This is where it can query for any required services and load content.
        /// </summary>
        public override void Initialize()
        {
            // TODO: Add your initialization code here

            base.Initialize();
            direction = Vector3.Forward;
        }


        /// <summary>
        /// Allows the game component to update itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Update(GameTime gameTime)
        {
            // TODO: Add your update code here

            base.Update(gameTime);
            Camera camera = (Camera)Game.Services.GetService(typeof(Camera));
            if (camera is ChaseCamera)
            {
                ChaseCamera cCamera = (ChaseCamera)camera;
                cCamera.UpdateWorldPositions(this);
            }
        }

        public override void Draw(GameTime gameTime)
        {
            base.Draw(gameTime);
            Matrix[] transforms = new Matrix[myShip.Bones.Count];
            myShip.CopyAbsoluteBoneTransformsTo(transforms);
            var translation = Matrix.CreateTranslation(position);
            Camera camera = (Camera)Game.Services.GetService(typeof(Camera));
            foreach (ModelMesh mesh in myShip.Meshes)
            {
                foreach (BasicEffect effect in mesh.Effects)
                {
                    effect.EnableDefaultLighting();
                    effect.View = camera.View;
                    effect.Projection = camera.Projection;
                    effect.World = transforms[mesh.ParentBone.Index] * translation;
                }
                if (isGround || isStair)
                {
                    Ray ray = new Ray(camera.Position / 4096f, Vector3.Down);
                    float? d = mesh.BoundingSphere.Intersects(ray);
                    if (d != null && d > 0 && d < 170)
                        camera.Move(new Vector3(0, (float)d, 0), true);
                }
                mesh.Draw();
            }
        }

        #region IPositionnable Membres

        private string name;

        public string Name
        {
            get { return name; }
            set { name = value; }
        }

        #endregion

        #region IMoveable Membres

        private Vector3 direction;

        public Vector3 Direction
        {
            get { return direction; }
            set { direction = value; }
        }

        public void Move(float d)
        {
        }

        public void Move(Vector3 destination, bool relative)
        {
            if (relative)
                Move(destination);
        }

        public void Move(Vector3 relativeDestination)
        {
        }

        #endregion
    }
}


